home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
wb
/
czesc_4
/
wbtitle
/
source
/
wbtitle.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-03
|
12KB
|
507 lines
/*
* WBTitle
*
* Version 1.0
*
* Public Domain Software
*
* This program replaces the Amiga's Workbench title bar so that it
* shows all types of memory available: Chip, Public, VM, and Retina.
*/
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/retina.h>
#include <proto/vmm.h>
#include <clib/alib_protos.h>
// The SetWindowTitles function offset
#define SWTOffset -276
enum {
JMPINSTR = 0x4ef9
};
typedef struct JmpEntry {
UWORD Instr;
APTR Func;
} JmpEntry;
static BOOL Replace(void);
static void Restore(void);
static void __asm new_SetWindowTitles(register __a0 struct Window *,
register __a1 UBYTE *, register __a2 UBYTE *,
register __a6 struct Library *);
static void NumberToString(ULONG number);
static void format_number(ULONG number);
static void no_lead_triple(ULONG number);
static void lead_triple(ULONG number);
// Global variables
struct RetinaBase *RetinaBase;
struct Library *VMMBase;
// Local variables
static char verstring[] = "$VER: WBTitle 1.0 " __AMIGADATE__;
static char port_name[] = "WBTitle";
static void __asm (*old_SetWindowTitles)(register __a0 struct Window *,
register __a1 UBYTE *,
register __a2 UBYTE *,
register __a6 struct Library *);
static JmpEntry *SWTEntry;
static char *chip_str, *fast_str, *public_str, *total_str, *virtual_str;
static char *retina_str, *memorder_str, *prefix_str, *suffix_str, *labels_str;
static char *comma_str, *mem_str, *last_str, *buff_ptr;
static char num_buf[14], comma;
static int units, num_size, mem_str_len, prefix_str_len;
static BOOL sep1000, labels_after;
/*
* The main method for replacing an Amiga OS function as safe as
* possible is to place the function with a jump table that is
* allocated. While the function is replaced, the jump table simply
* jumps to my routine:
*
* jmp _new_SetWindowTitles
*
* When the user asks the program to quit, we can't simply put the
* pointer back that SetFunction() gives us since someone else might
* have replaced the function. So, we first see if the pointer we
* get back points to the out jump table. If so, then we _can_ put
* the pointer back like normal (no one has replaced the function
* while we has it replaced). But if the pointer isn't mine, then
* we have to replace the jump table function pointer to the old
* function pointer:
*
* jmp _old_SetWindowTitles
*
* Finally, we only deallocate the jump table _if_ we did not have
* to change the jump table.
*/
main(int argc, char *argv[])
{
struct MsgPort *port;
// FindPort() Forbid()
Forbid();
port = FindPort(port_name);
if (port) {
struct MsgPort *reply_port;
// Create a reply port
reply_port = CreateMsgPort();
if (reply_port) {
struct Message msg;
// Set fields in message structure
msg.mn_ReplyPort = reply_port;
msg.mn_Length = sizeof(struct Message);
// Send the message
PutMsg(port, &msg);
// Finished with port, so stop FindPort() Forbid()
Permit();
// Wait for a reply
do {
WaitPort(reply_port);
} while (GetMsg(reply_port) == NULL);
// Clear and Delete reply_port Forbid()
Forbid();
// Clear any messages
while (GetMsg(reply_port));
// Delete the reply port
DeleteMsgPort(reply_port);
// Clear and Delete reply_port stop Forbid()
Permit();
} else {
// Finished with port, so stop FindPort() Forbid()
Permit();
}
} else if (port = CreateMsgPort()) {
struct Message *msg;
char **ttypes;
// Finished with port, so stop FindPort() Forbid()
Permit();
// Setup quitting port
port->mp_Node.ln_Name = port_name;
port->mp_Node.ln_Pri = -120;
// Add quitting port to public list
AddPort(port);
// Open the Retina library
RetinaBase = (struct RetinaBase *)OpenLibrary("retina.library", 0);
// Check on VMM; look for port, and alloc signal
if (FindPort("VMM_Port")) {
VMMBase = OpenLibrary("vmm.library", 0);
}
// Setup to read some arguements
ttypes = ArgArrayInit(argc, argv);
// Read some arguments
prefix_str = ArgString(ttypes, "PREFIX", "Amiga Workbench ");
suffix_str = ArgString(ttypes, "SUFFIX", "");
labels_str = ArgString(ttypes, "LABELS", "AFTER");
chip_str = ArgString(ttypes, "CHIP", " Chip ");
fast_str = ArgString(ttypes, "FAST", " Fast ");
public_str = ArgString(ttypes, "PUBLIC", " Public ");
total_str = ArgString(ttypes, "TOTAL", " Total ");
virtual_str = ArgString(ttypes, "VIRTUAL", " Virtual ");
retina_str = ArgString(ttypes, "RETINA", " Retina ");
memorder_str = ArgString(ttypes, "MEMORDER", "CVPR");
sep1000 = (ArgString(ttypes, "THOUSANDSEP", NULL) != NULL);
units = ArgInt(ttypes, "UNITS", 1);
comma_str = ArgString(ttypes, "SEPERATOR", NULL);
if (comma_str && comma_str[0]) {
comma = comma_str[0];
} else {
comma = ',';
}
labels_after = (stricmp(labels_str, "BEFORE") != 0);
if (units < 0) {
units = 1;
}
// Compute the size of numbers
{
ULONG maxnum = 0xffffffff;
// Compute the number of digits
maxnum /= units;
while (maxnum) {
maxnum /= 10;
num_size++;
}
// Compute the number of commas
if (sep1000) {
int com = num_size;
while (com > 3) {
num_size++;
com -= 3;
}
}
}
// Compute the size of the mem string
{
ULONG i = 0;
char ch;
// Add in the prefix string size
mem_str_len = prefix_str_len = strlen(prefix_str);
// Add in the memory parts
while (ch = toupper(memorder_str[i])) {
switch (ch) {
case 'C':
mem_str_len += strlen(chip_str) + num_size;
break;
case 'F':
mem_str_len += strlen(fast_str) + num_size;
break;
case 'P':
mem_str_len += strlen(public_str) + num_size;
break;
case 'T':
mem_str_len += strlen(total_str) + num_size;
break;
case 'V':
if (VMMBase) {
mem_str_len += strlen(virtual_str) + num_size;
}
break;
case 'R':
if (RetinaBase) {
mem_str_len += strlen(retina_str) + num_size;
}
break;
}
i++;
}
// Add in the suffix string size
mem_str_len += strlen(suffix_str);
}
if (mem_str_len > 0) {
// Allocate the memory
mem_str = AllocMem(mem_str_len + 1, MEMF_PUBLIC);
if (mem_str) {
strcpy(mem_str, prefix_str);
last_str = &mem_str[prefix_str_len];
// Attempt to replace function
if (Replace()) {
// Wait for someone to signal me to quit
do {
WaitPort(port);
msg = GetMsg(port);
} while (msg == NULL);
ReplyMsg(msg);
// Restore function
Restore();
}
FreeMem(mem_str, mem_str_len + 1);
}
}
// Cleanup from reading arguments
ArgArrayDone();
// Remove port from public access
RemPort(port);
// Clear and Delete port Forbid()
Forbid();
// Clear the port of messages
while (msg = GetMsg(port)) {
ReplyMsg(msg);
}
// Closedown quitting port
DeleteMsgPort(port);
// Clear and Delete port stop Forbid()
Permit();
}
}
static BOOL Replace(void)
{
// Allocate the jump table
SWTEntry = AllocMem(sizeof(JmpEntry), 0);
if (SWTEntry) {
// Replacement Forbid()
Forbid();
// Replace the function with pointer to jump table
old_SetWindowTitles = SetFunction((struct Library *)IntuitionBase,
SWTOffset, (ULONG (*)())SWTEntry);
// Setup the jump table
SWTEntry->Instr = JMPINSTR;
SWTEntry->Func = new_SetWindowTitles;
// Clear the cpu's cache so the execution cache is valid
CacheClearU();
// Stop the replacement Forbid()
Permit();
return TRUE;
} else {
return FALSE;
}
}
static void Restore(void)
{
BOOL my_table;
ULONG (*func)();
// Fix back Forbid()
Forbid();
// Put old pointer back and get current pointer at same time
func = SetFunction((struct Library *)IntuitionBase, SWTOffset,
(ULONG (*)())old_SetWindowTitles);
// Check to see if the pointer we get back is ours
if ((JmpEntry *)func != SWTEntry) {
// If not, leave jump table in place
my_table = FALSE;
SetFunction((struct Library *)IntuitionBase, SWTOffset,
func);
SWTEntry->Func = old_SetWindowTitles;
} else {
// If so, free the jump table
my_table = TRUE;
FreeMem(SWTEntry, sizeof(JmpEntry));
}
// Clear the cpu's cache so the execution cache is valid
CacheClearU();
// Stop fix back Forbid()
Permit();
// Let the user know if the jump table couldn't be freed
if (!my_table) {
DisplayBeep(NULL);
}
// Wait 5 seconds to try and guarantee that all tasks have
// finished executing inside my replacement function before
// quitting. There's no real way to guarantee, though.
Delay(250);
}
static void __saveds __asm new_SetWindowTitles(
register __a0 struct Window *window,
register __a1 UBYTE *win_title,
register __a2 UBYTE *scr_title,
register __a6 struct Library *lib)
{
if (scr_title && (scr_title != (UBYTE *)0xffffffff) &&
(*scr_title == 'A') && strstr(scr_title, "graphics mem")) {
ULONG i = 0;
char ch;
// Set last_str to nothing
*last_str = 0;
// Add in the memory parts
while (ch = toupper(memorder_str[i])) {
switch (ch) {
case 'C':
if (!labels_after) {
strcat(last_str, chip_str);
}
NumberToString(AvailMem(MEMF_CHIP));
strcat(last_str, num_buf);
if (labels_after) {
strcat(last_str, chip_str);
}
break;
case 'F':
if (!labels_after) {
strcat(last_str, fast_str);
}
NumberToString(AvailMem(MEMF_FAST));
strcat(last_str, num_buf);
if (labels_after) {
strcat(last_str, fast_str);
}
break;
case 'P':
if (!labels_after) {
strcat(last_str, public_str);
}
NumberToString(AvailMem(MEMF_PUBLIC));
strcat(last_str, num_buf);
if (labels_after) {
strcat(last_str, public_str);
}
break;
case 'T':
if (!labels_after) {
strcat(last_str, total_str);
}
NumberToString(AvailMem(0));
strcat(last_str, num_buf);
if (labels_after) {
strcat(last_str, total_str);
}
break;
case 'V':
if (VMMBase) {
if (!labels_after) {
strcat(last_str, virtual_str);
}
NumberToString(AvailVMem(0));
strcat(last_str, num_buf);
if (labels_after) {
strcat(last_str, virtual_str);
}
}
break;
case 'R':
if (RetinaBase) {
if (!labels_after) {
strcat(last_str, retina_str);
}
NumberToString(Retina_AvailMem(0));
strcat(last_str, num_buf);
if (labels_after) {
strcat(last_str, retina_str);
}
}
break;
}
i++;
}
strcat(last_str, suffix_str);
old_SetWindowTitles(window, win_title, mem_str, lib);
} else {
old_SetWindowTitles(window, win_title, scr_title, lib);
}
}
/*
* Convert the number to a string in the format the user specified.
* The string generated is 0 terminated.
*
* Uses global variables: buff_ptr, num_buff
*/
static void NumberToString(ULONG number)
{
number /= units;
if (sep1000) {
buff_ptr = num_buf;
format_number(number);
*buff_ptr = 0;
} else {
stcul_d(num_buf, number);
}
}
static void format_number(ULONG number)
{
if (number > 1000) {
format_number(number / 1000);
lead_triple(number % 1000);
} else {
no_lead_triple(number);
}
}
static void no_lead_triple(ULONG number)
{
if (number > 10) {
no_lead_triple(number / 10);
*buff_ptr++ = ((number % 10) | 0x30);
} else {
*buff_ptr++ = (number | 0x30);
}
}
static void lead_triple(ULONG number)
{
*buff_ptr++ = comma;
*buff_ptr++ = ((number / 100) | 0x30);
number %= 100;
*buff_ptr++ = ((number / 10) | 0x30);
number %= 10;
*buff_ptr++ = (number | 0x30);
}